/* 
 * File:   TitleList.cpp
 * Author: yanex
 */

#include "TitleList.h"
#include "Title.h"

string trim(string& s, const string& drop = " ")
{
    string r=s.erase(s.find_last_not_of(drop)+1);
    return r.erase(0,r.find_first_not_of(drop));
}

//Reading the file, filling the list
TitleList::TitleList(string filename) : watchedCount(0), todoCount(0) {
    this->filename=filename;
    items.clear();
    
    ifstream file;
    file.open(filename.c_str());

    if (!file) {
        cerr << "File \"" << filename << "\" not found.\nAborting.";
        exit(1);
    }

    int mode=0;
    double length, time;
    string s, donemarker = "#done";
    while (file.good()) {
        switch (mode)
        {
            case 0: //TODO
                getline(file, s);
                if (s==donemarker) {
                    mode=1;
                    break;
                }

                if (s.length()>2) {
                    Title temp(s, 0.0, 25, ANIME_TODO);
                    items.push_back(temp);
                    todoCount++;
                }
                break;
            case 1: //WATCHED
                length=time=-1;
                file >> length;
                if (length<0) break;
                
                getline(file, s);
                s=trim(s);
                if (s.length()>2) {
                    const size_t space = s.find(" ");
                    char *msymbol;
                    if (space!=string::npos && space>0) {
                        string timespec=s.substr(0, space);
                        if (timespec.length()>1 && testTimeMarker(timespec)) {
                            //Time'll be 0 if the marker is invalid. Stupid user is to blame
                            time=-1, time=atof(timespec.substr(1, timespec.length()-1).c_str());
                            s=s.substr(space+1, s.length()-space-1);
                        }
                    }
                    
                    //If there's no time marker
                    if (time<=0)
                        time=DEFAULT_TIME;

                    Title temp(trim(s), length, time, ANIME_WATCHED);
                    items.push_back(temp);
                    t+=length*time;
                    watchedCount++;
                }
                break;
        }
    }
    file.close();
}

//Return 1 if the string seems to be a marker
inline int TitleList::testTimeMarker(string test) {
    return toupper(test[test.length()-1])=='M' && test[0]=='#';
}

//Return titles count
int TitleList::count(int type) {
    switch (type) {
        case ANIME_WATCHED:
            return watchedCount;
        case ANIME_TODO:
            return todoCount;
        case ANIME_ALL:
            return watchedCount+todoCount;
    }
}

//Return watched time
double TitleList::time(int type) {
    switch (type) {
        case TIME_MINUTE:
            return t;
        case TIME_HOUR:
            return t/60;
        case TIME_DAY:
            return t/60/24;
        case TIME_MONTH:
            return t/60/24/30;
        case TIME_YEAR:
            return t/60/24/30/365;
    }
}

//Just get ABCDEF from abCDEf
string stoupper(string s)
{
    string ret=s;
    string::iterator i=ret.begin(),
                          end=ret.end();
    while (i!=end) {
        *i=toupper((int)*i);
        ++i;
    }
    return ret;
}

//Search for the title name
void TitleList::check(string title, ostream& stream) {
    int count=0;
    
    title=stoupper(title);
    vector<Title>::iterator it;
    it=items.begin();
    while (it!=items.end()) {
        if (stoupper((*it).getName()).find(title)!=string::npos) {
            stream << (*it).getName() << "\n";
            if ((*it).getType()==ANIME_WATCHED)
                stream << "Watched: " << (*it).getLength() << " ep.\n" <<
                          "Runtime: " << (*it).getTime() << " min.\n";
            else
                stream << "Planned to watch.\n";
            count++;
        }
        ++it;
    }
    if (!count)
        stream << "Not found.\n";
}

//Filesave function
void TitleList::save() {
    ofstream file;
    file.open(filename.c_str());

    if (!file) {
        cerr << "File \"" << filename << "\" not available for writing.\nAborting.";
        exit(1);
    }

    vector<Title>::iterator it;
    it=items.begin();
    while (it!=items.end()) {
        if ((*it).getType()==ANIME_TODO)
            file << (*it).getName() << "\n";
        ++it;
    }

    file << "\n#done\n";
    it=items.begin();
    while (it!=items.end()) {
        if ((*it).getType()==ANIME_WATCHED) {
            file << (*it).getLength() << " ";
            if ((*it).getTime()!=25)
                file << "#" << (*it).getTime() << "m ";
            file << (*it).getName() << "\n";
        }
        ++it;
    }

    file.close();
}

//Add new title
void TitleList::add(string param, string title) {
    double time=25, length=0, type=ANIME_TODO;

    string t="";
    for (int i=0; i<param.length(); i++) {
        if (param[i]>='0' && param[i]<'9')
            t+=param[i];
        else {
            switch (param[i]) {
                case 'w': //WATCHED
                    type=ANIME_WATCHED;
                    break;
                case 't': //TODO
                    type=ANIME_TODO;
                case 'l': //length
                    if (t.length()>0)
                        length=atof(t.c_str());
                    break;
                case 'r': //runtime
                    if (t.length()>0)
                        time=atof(t.c_str());
                    break;
                default: ;
            }
            t="";
        }
    }
    
    Title temp(title, length, time, type);
    items.push_back(temp);
    save();
}

//Change title parameters
void TitleList::set(string param, string title) {
    double time=25, length=0, type=ANIME_TODO;
    title=stoupper(title);

    int count=0;
    vector<Title>::iterator it, fnd;
    it=items.begin();
    while (it!=items.end()) {
        if (stoupper((*it).getName()).find(title)!=string::npos) {
            if (count>0) {
                cerr << "Multiple results. Aborting.\n";
                return;
            } else
                fnd=it, ++count;
        }
        ++it;
    }

    if (count==0) {
        cerr << "Not found. Aborting.\n";
        return;
    }

    time=(*fnd).getTime();
    length=(*fnd).getLength();
    type=(*fnd).getType();

    string t="";
    for (int i=0; i<param.length(); i++) {
        if (param[i]>='0' && param[i]<'9')
            t+=param[i];
        else {
            switch (param[i]) {
                case 'w': //watched
                    type=ANIME_WATCHED;
                    break;
                case 't': //todo
                    type=ANIME_TODO;
                case 'l': //length
                    if (t.length()>0)
                        length=atof(t.c_str());
                    break;
                case 'r': //runtime
                    if (t.length()>0)
                        time=atof(t.c_str());
                    break;
                default: ;
            }
            t="";
        }
    }

    (*fnd).setLength(length);
    (*fnd).setTime(time);
    (*fnd).setType(type);
    save();
}

//Print user's titles
void TitleList::print(int type, ostream& stream) {
    vector<Title>::iterator it;
    it=items.begin();
    while (it!=items.end()) {
        if (type==ANIME_ALL || type==(*it).getType())
            stream << (*it).getName() << "\n";
        ++it;
    }
}

TitleList::~TitleList() {
    items.clear();
}
